Задачки с решения ;)

“Примерна” задача №8.

#include <iostream>
using namespace std;

#define M 100
typedef float ElementType;

struct Queue
{
    int f;  //номер на фиктивен елемент
			//преди началото на опашката.
    int r;  //номер на eлементa в края на опашката.

	ElementType QueueArray[M];
};

void enqueue(Queue *q, ElementType x)
{
    if ((q->r + 1) % M == q->f)
    {
        cout << "StackOverflowException: "
			<< "Index is greater than the maximum size!" << endl;
        exit(1);
    }

	q->r = (q->r + 1) % M;
    q->QueueArray[q->r] = x;
}

int main()
{
    Queue queue;
    queue.f = 0;
	queue.r = 0;
    cout << queue.r << endl;

	for (int index = 0; index < M; index++)
    {
		enqueue(&queue, index);
        cout << queue.r << endl;
    }

    return 0;
}

Output-а на програмата:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
StackOverflowException: Index is greater than the maximum size!

Забележка: Не забравяйте за кирилизацията.

Реалният фрагмент от код.

#include <iostream>
using namespace std;

#define M 100
typedef float ElementType;

struct Queue
{
    int f;  //номер на фиктивен елемент
			//преди началото на опашката.
    int r;  //номер на eлементa в края на опашката.

	ElementType QueueArray[M];
};

void enqueue(Queue *q, ElementType x)
{
    if ((q->r + 1) % M == q->f)
    {
        cout << "ПРЕПЪЛВАНЕ" << endl;
        exit(1);
    }

	...
    q->QueueArray[q->r] = x;
}

int main()
{
    Queue queue;
    queue.f = 0;
	queue.r = 0;
    cout << queue.r << endl;

	for (int index = 0; index < M; index++)
    {
		enqueue(&queue, index);
        cout << queue.r << endl;
    }

    return 0;
}

Обяснението на фрагмента от код и пропуските в него са:

Не се плашете от първия ред на фрагмента от код, но там дефинираме константа с име М и стойност 100, която ще служи за максимален размер на опашката.
Имаме структура Queue, която има данни, служещи за следене на началото и края на опашката. Масивът от числа с плаваща запетая е, за да пазим последователността от елементи, в него се записват самите стойностите на данните, които желаем да добавим в опашката, за разлика от променливите f и r.

Опашката е структура от данни, която добавя данните си отзад, а ги изтрива в обратен ред. Първият влязъл е първият излязъл.

Операциите за въвеждане и изваждане на елементи от него са: enqueue и dequeue.

Функцията enqueue:
Първата работа е да проверим дали можем да добавим елемент. По принцип същото нещо може да се ползва и от опашката, но ще спазим “добрата концепция” на Павлов. Ако се окаже, че остатъка от деление даде нулевия елемент, се извежда съобщение за грешка и програмата спира. Ако ли не увеличаваме индекса и след това се добавя конкретната стойност на този елемент.

« 1 2 3 4 5 6 7 8 »

Задачки с решения ;)

“Примерна” задача №7.

#include <iostream>
using namespace std;

#define M 100

struct Stack
{
    int t;  //номер на елемента във върха на стека
    float stack_array[M];
};

void push(Stack *s, float x)
{
    s->t++;
    if (s->t > M)
    {
        cout << "StackOverflowException: "
			<< "Index is greater than the maximum size!" << endl;
        exit(1);
    }

    s->stack_array[s->t - 1] = x;
}

float pop(Stack *s)
{
    if (s->t == 0)
    {
        cout << "OutOfRangeException: "
			<< "Index is less than the minimum size!" << endl;
        exit(1);
    }

    s->t--;

    return s->stack_array[s->t];
}

int main()
{
    Stack stack;
    stack.t = 0;
    cout << stack.t << endl;

    //Ако index расте до <= M,
	//ще бъде предизвикана StackOverflowException
    for (int index = 0; index < M; index++)
    {
        push(&stack, index + index * 0.1f);
        cout << stack.t << endl;
    }

    for (int index = 0; index <= M; index++)
    {
        pop(&stack);
        cout << stack.t << endl;
    }

    return 0;
}

Output-а на програмата:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
99
98
97
96
95
94
93
92
91
90
89
88
87
86
85
84
83
82
81
80
79
78
77
76
75
74
73
72
71
70
69
68
67
66
65
64
63
62
61
60
59
58
57
56
55
54
53
52
51
50
49
48
47
46
45
44
43
42
41
40
39
38
37
36
35
34
33
32
31
30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
OutOfRangeException: Index is less than the minimum size!

Забележка: Не забравяйте за кирилизацията.

Реалният фрагмент от код.

#include <iostream>
using namespace std;

#define M 100

struct Stack
{
	int t;	//номер на елемента във върха на стека
	float stack_array[M];
};

void push(Stack *s, float x)
{
	...

	if (s->t > M)
	{
		cout << "\nПРЕПЪЛВАНЕ\n";
		exit(1);
	}

	s->stack_array[s->t - 1] = x;
}

float pop(Stack *s)
{
	...

	s->t--;

	return s->stack_array[s->t];
}

Обяснението на фрагмента от код и пропуските в него са:

Не се плашете от първия ред на фрагмента от код, но там дефинираме константа с име М и стойност 100, която ще служи за максимален размер на стека.
Имаме структура Stack, която има данна, служеща за отчитане на броя на елементите. Масивът от числа с плаваща запетая е, за да пазим последователността от елементи, в него се записват самите стойностите на данните, които желаем да добавим в стека, за разлика от променливата t.

Стекът е структура от данни, която добавя данните си отпред или най-отгоре, а ги изтрива в обратен ред. Последният влязъл е първият излязъл.

Операциите за въвеждане и изваждане на елементи от него са: push и pop.

Сега към функцията push:
Първата работа като добавим елемент е да увеличим броя на елементите, а понеже t ни служи точно като брояч, за това на мястото на многоточието поставяме операцията t++;.

Проверката служи да проверим дали ще можем да добавим нов елемент, но ако е достигнал максимум-а ще ни изведе съобщение за препълване и ще прекъснем програмата. Ако нямаме препълване се добавя нов елемент.

Функция pop:
Първата работа на мястото на многоточието трябва да проверим дали не сме достигнали минимума на стека. Ако е достигнат извежда съобщение за грешка, че сме излезли извън големината на стека. След това трябва да прекъснем програмата. Останалото е аналогично на по-горе. Намаляваме броя на елементите и връщаме новия последен елемент.

« 1 2 3 4 5 6 7 8 »

Задачки с решения ;)

“Примерна” задача №6.

#include <iostream>
using namespace std;

struct Student
{
	long nomer;	//Факултетен номер
	float sr_uspeh;	//Среден успех
	Student *next;
};

//first - указател към начало на свързания списък
//key - ключ, факултетния номер се разглежда като ключ
//value - стойност, която ще актуализира средния успех
void search(Student *first, long key, float value)
{
	Student *ptr = first;
	
	while (ptr)
	{
		if (ptr->nomer == key)
		{
			break;
		}
		else
		{
			ptr = ptr -> next;
		}
	}

	if (ptr)
	{
		cout << "Студент с факултетен № " << first->nomer 
		   << " и среден успех: " << first->sr_uspeh << endl;

		ptr->sr_uspeh = value;

		cout << "Студент с факултетен № " << first->nomer 
		   << " и среден успех: " << first->sr_uspeh << endl;
	}
	else
	{
		cout << "\nНяма елемент с указания ключ.";
	}
}

int main()
{
	Student student1, student2;
	student1.nomer = 12345;
	student1.sr_uspeh = 4.78;
	student1.next = &student2;
	student2.nomer = 54321;
	student2.sr_uspeh = 5.99;
	student2.next = NULL;

	search(&student1, 12345, 5.12);
	search(&student1, 12345, 4);
	search(&student2, 54321, 5.00);
	search(&student2, 353253, 5.00);

	return 0;
}

Output-а на програмата:

Студент с факултетен № 12345 със среден успех: 4.78
Студент с факултетен № 12345 със среден успех: 5.12
Студент с факултетен № 12345 със среден успех: 5.12
Студент с факултетен № 12345 със среден успех: 4
Студент с факултетен № 54321 със среден успех: 5.99
Студент с факултетен № 54321 със среден успех: 5

Няма елемент с указания ключ.

Забележка: Не забравяйте за кирилизацията.

Реалният фрагмент от код.

struct Student
{
	long nomer;		//Факултетен номер
	float sr_uspeh;	//Среден успех
	Student *next;
};

//first - указател към начало на свързания списък
//key - ключ, факултетния номер се разглежда като ключ
//value - стойност, която ще актуализира средния успех
void search(Student *first, long key, float value)
{
	Student *ptr = first;
	
	while (ptr)
	{
		if (ptr->nomer == key)
		{
			..........
		}
		else
		{
			..........
		}
	}

	if (ptr)
	{
		ptr->sr_uspeh = value;
	}
	else
	{
		cout << "\nНяма елемент с указания ключ.";
	}
}

Обяснението на фрагмента от код и пропуските в него са:

Няма да обяснявам работата на програмата, тя е просто за визуализация, че всичко е ОК и как сработва. Сега директно към фрагмента от код. След като намерим даден елемент е хубаво да спрем да го търсим, затова слагаме break; и излизаме от цикъла, ако не го намерим трябва да го насочим към следващия и цикъла ще свърши или като го намери или като указателя посочи NULL.

« 1 2 3 4 5 6 7 8 »

Задачки с решения ;)

“Примерна” задача №5.

#include <iostream>
using namespace std;

struct CN
{
	char character;
	CN *next;
} *first, cn;

void list(char *word)
{
	cn.character = *word;
	cn.next = first;
	first = new CN;
	*first = cn;

	if (*word)
	{
		list(word + 1);
	}
}

void print(CN *first)
{
	if (!first)
	{
		cout << "\n result = ";
	}
	else
	{
		print(first->next);
		cout << first->character;
	}
}

int main()
{
	first = NULL;
	list("droll");
	print(first->next->next);

	return 0;
}

Output-а на програмата:


 result = drol

Обяснението за последователността на изпълнението на програмата е следното:

Първо се нулира обекта first от структурата CN. След това извикваме функцията list с параметър низа “droll”. Във функцията list, чрез пряка рекурсия, се създава свързан списък, като елементите са от символите от подадения низ.

Малко по-детайлно обяснение на функцията list. Ролята на обекта cn от CN е само да взима първия символ от низа и да задава предходния елемент. first от своя страна взима вече готовия елемент, копира го и го добавя като нов елемент на структурата. След това проверката ни служи за дъно на рекурсията, тъй като все някога свършва низа. Ако низа не е свършил извикваме отново функцията със същия низ, но без първия символ. След като свърши низа последния елемент е със следните параметри: first->character = ‘\ 0’ и first->next = ‘l’.

Сега преминаваме към функцията print. В частния случай ние извикваме
(first->next)->next, ще се опитам да го обясня по-разбираемо:
first->character = ‘\ 0’
first->next = ‘l’, като това ще го кръстим previous (previous->character = ‘l’ и previous->next = ‘l’)
first->next->next = previous->next = ‘l’
Реално ние като извикваме първоначално функцията print ще и подадем елемента ‘l’, а не ‘\ 0’, тъй като сме се преместили 2 елемента наляво (нищо, че операцията се казва next, явно Павлов вирее в арабския свят – там се пише отдясно наляво).
Влизаме във функцията и проверяваме дали текущия елемент не е различен от NULL, ако не е извикваме, чрез пряка рекурсия, функцията с параметър предходния на текущия елемент (first->next). Това го правим докато не достигнем предходния елемент на ‘d’, който NULL и тогава извеждаме “\n result = “, а след това се връщаме обратно по пътя на рекурсията и печатаме символите от ‘d’ до първото ‘l’, защото първоначално извикваме функцията с този параметър.

Забележка: Защо достъпваме елементите на first със “->”, а не cn с “.”, защото first е указател към обект, а cn e самият обект.

« 1 2 3 4 5 6 7 8 »

Задачки с решения ;)

“Примерна” задача №4.

#include <iostream>
using namespace std;

class Date
{
public:
	Date(int day = 1, int month = 1, int year = 1)
	{
		this->day = day;
		this->month = month;
		this->year = year;
	}

	void Print()
	{
		cout << "Day: " << this->day
		   << " Month: " << this->month
		   << " Year: " << this->year << endl; 	
	}

	Date operator++(int); 
private: 	
	int day;	//Ден 	
	int month;	//Месец 	
	int year;	//Година 	

	void helpIncrement(); 	
	//Обслужваща функция за увеличаване 	
	//на датата с един ден.
};

Date Date::operator++(int dummy) 
{ 	
	Date temp = *this;
	helpIncrement();

	return temp;
}

void Date::helpIncrement() 
{ 	
	this->day++;
}

int main()
{
	Date date(10, 10, 10);
	date.Print();
	(date++).Print();
	date.Print();

	return 0;
}

Output-а на програмата:

Day: 10 Month: 10 Year: 10
Day: 10 Month: 10 Year: 10
Day: 11 Month: 10 Year: 10

Забележка: Програмата е модифицирана повече, от колкото е реалния фрагмент от код.

Ето и реалния фрагмент от код, като въпроса към него, какъв е проблема.

#include <iostream>
using namespace std;

class Date
{
public:
	...

	Date& operator++(int);
private:
	int month;	//Месец
	int day;	//Ден
	int year;	//Година

	void helpIncrement();
	//Обслужваща функция за увеличаване
	//на датата с един ден.
};

Date& Date::operator++(int)
{
	Date temp = *this;
	helpIncrement();

	return temp;
}

Обяснението на програмата е следното:

Няма да се пускам в обяснение на работата на класа, а директно към проблема във фрагмента. Eдинствената грешка, е липсата на име на променливата, която подаваме в дефиницията на operator++. Други грешки по време на компилация или изпълнение няма да получим, но пък не е правилно да връщаме псевдоним на датата, вместо същия обект, за това оправяме фрагмента, да не връща Date&, а Date.

« 1 2 3 4 5 6 7 8 »

Задачки с решения ;)

“Примерна” задача №3.

#include <iostream>
using namespace std;

class Point
{
public:
	Point(float = 0, float = 0);
	~Point();
protected:
	float x, y;
};

Point::Point(float a, float b)
{
	x = a;
	y = b;

	cout << "Constructor of Point: "
		<< '[' << a << ", " << b << ']' << endl;
}

Point::~Point()
{
	cout << "Destructor of Point: "
		<< '[' << x << ", " << y << ']' << endl;
}

class Circle : public Point
{
public:
	Circle(float r = 0.0, float x = 0.0, float y = 0.0);
	~Circle();
private:
	float radius;
};

Circle::Circle(float r, float a, float b)
	: Point(a, b)
{
	radius = r;

	cout << "Constructor of Circle: "
		<< radius << '[' << a << ", " << b << ']' << endl;
}

Circle::~Circle()
{
	cout << "Destructor of Circle: "
		<< radius << '[' << x << ", " << y << ']' << endl;
}

int main()
{
	{
		Point p(1.1f, 2.2f);
	}
	Circle circle1(4.5, 7.2f, 2.9f);
	Circle circle2(10, 5, 5);

	return 0;
}

Output-а на програмата:

Constructor of Point: [1.1, 2.2]
Destructor of Point: [1.1, 2.2]
Constructor of Point: [7.2, 2.9]
Constructor of Circle: 4.5[7.2, 2.9]
Constructor of Point: [5, 5]
Constructor of Circle: 10[5, 5]
Destructor of Circle: 10[5, 5]
Destructor of Point: [5, 5]
Destructor of Circle: 4.5[7.2, 2.9]
Destructor of Point: [7.2, 2.9]

Забележка: Ако конзолата не е кирилизирана, ще излязат интересни символи, на мястото на кирилицата. В програмата на Павлов, коментарите са на кирилица, така че може да се заяде, ако го вземете дословно от output-а. Също така друга важна забележка е, че примерните данни изрично трябва да се даде suffix(това, което седи след стойнността) f, защото double e по-голям тип от float и трябва да се cast-не изрично. Ако не е подаден ще даде компилационна грешка, но може и да не го поправяте в примера на Павлов, ако не е изрично казано.

Обяснението за последователността на изпълнението на програмата е следното:

Тук нищо сложно, изпълняваме конструктора на обект от тип Point, но понеже е сложен в тяло (scope), след излизане от него се извиква деструктора му, защото обекта съществува само в конкретното тяло (scope). След това си създаваме два обекта от тип Circle, а понеже Circle наследява Point се извиква конструктора на Point, а след това на Circle. Това се прави 2 пъти, защото създаваме два обекта от тип Circle. След като приключи програмата се извикват деструкторите на circle2, point2, circle1, point1 -> т.е. обратен на реда на създаването им. Важно е да се отблежи, че унищожаването става след завършване на програмата, като това може да се провери като си пуснете изпълнимия файл и в отделна конзола, за да се забележат разликите.

Конструкторите винаги се изпълняват от родителя -> наследника,

докато при деструкторите е обратното от наследника -> родителя.

« 1 2 3 4 5 6 7 8 »

Задачки с решения ;)

“Примерна” задача №2.

#include <iostream>
using namespace std;

class PoweredDevice
{
public:
	PoweredDevice(int nPower)
	{
		cout << "PoweredDevice: " << nPower << endl;
	}
};

class Scanner : virtual public PoweredDevice
{
public:
	Scanner(int nScanner, int nPower)
		: PoweredDevice(nPower)
	{
		cout << "Scanner: " << nScanner << endl;
	}
};

class Printer : virtual public PoweredDevice
{
public:
	Printer(int nPrinter, int nPower)
		: PoweredDevice(nPower)
	{
		cout << "Printer: " << nPrinter << endl;
	}
};

class Copier : public Scanner, public Printer
{
public:
	Copier(int nScanner, int nPrinter, int nPower)
		: Scanner(nScanner, nPower),
		Printer(nPrinter, nPower),
		PoweredDevice(nPower)
	{} //празно тяло, може и без него
};

int main()
{
	Copier cCopier(1, 2, 3);

	return 0;
}

Output-а на програмата:

PoweredDevice: 3
Scanner: 1
Printer: 2

Обяснението за последователността на изпълнението на програмата е следното:

Започваме със създаването на обект от клас-наследника Сopier, след това извикване на подходящия (единствения) конструктор на този клас, който реално нищо не прави освен да извика конкретните конструктори на своите родители (class Scanner, class Printer). Преди да ги изпълни се проверя дали съществуват родители на тези класове, тъй като техните конструктори извикват конструктора на техния общ родител (class PoweredDevice). Тук има една особеност понеже Scanner и Printer наследяват PoweredDevice (virtual public). Като следствие от наследяването ние не можем да създававаме обекти от класа, както и да се изпълняват неговите методи. Това е проблем, тъй като класовете-наследници Scanner и Printer, трябва да разширят класа-родител PoweredDevice, а те не могат директно да извикат конструктора му, нито да го предефинират. Затова ние в класа Copier, изрично извикваме конструктора на PoweredDevice, който е достъпен изцяло public, тъй като той се вижда през родителите на Copier, но пък виртуалното наследяване важи само за тях. Така след като изпълним конструктора на PoweredDevice, можем да продължим с извикването на останалите конструктори в реда им на наследяването им в декларацията на class Copier. Малко по-опростено казано след като се изпълни конструктора на PoweredDevice, нататък ще се извикат конструкторите в реда, в който са упоменати на първия ред на Copier преди тялото на класа.

Конструкторите винаги се изпълняват от родителя -> наследника,

докато при деструкторите е обратното от наследника -> родителя.

« 1 2 3 4 5 6 7 8 »

Задачки с решения ;)

“Примерна” задача №1.
Да имам и уникалното именуване на Павлов или на Бъчваров, даже не знам чие произведение са контролните.

#include <iostream>
using namespace std;

class A
{
public:
	A(int nValue)
	{
		cout << "A: " << nValue << endl;
	}
};

class B : public A
{
public:
	B(int nValue, double dValue) : A(nValue)
	{
		cout << "B: " << dValue << endl;
	}
};

class C : public B
{
public:
	C(int nValue, double dValue, char chValue)
		: B(nValue, dValue)
	{
		cout << "C: " << chValue << endl;
	}
};

int main()
{
	C cClass(5, 4.3, 'R');

	return 0;
}

Output-а на програмата:

A: 5
B: 4.3
C: R

Обяснението за последователността на изпълнението на програмата е следното:

Започваме със създаването на обект от клас-наследника С, но при извикване на подходящия (единствения) конструктор на този клас се извиква конструктора на своя родител (class B), а B от своя страна извиква конструктора на неговия родител (class A). В А е дъното на наследяването и за това първо се изпълнява неговия конструктор, и т.н. в обратен ред се изпълняват конструкторите на В и С. Всеки клас-наследник разширява своя родител, заради което при създаването първо се изпълнява конструктора на клас-родителя. При унищожаването е на обратно, първо се премахва разширената част на класа на наследника и след това общата от класа на родителя.

Конструкторите винаги се изпълняват от родителя -> наследника,

докато при деструкторите е обратното от наследника -> родителя.

« 1 2 3 4 5 6 7 8 »

Мечтата на Павлов

Тук давам различни примери за конструкцията switch най-вече такива от контролните по теория на Павел Павлов по “Увод в програмирането“.


#include <iostream>
using namespace std;

int main ()
{
	int x = 0;
	while (x < 5) 	{
		switch (x * (x > -1) * (x < 4))
		{
			case 1: cout << "A";
			case 2: cout << "B";
			case 3: cout << "C";
			default: cout << "Not a number";
		}
		cout << endl;
		x++;
	}

	system("pause");
	return 0;
}

Конструкцията switch в езика С++ има богати възможности да обърква студентите, а и не само тях. Тук можем да нямаме break-ове и така да изпълнява и ненужни неща. Също така можем да подредим default-а по различни начини, съчетано с липсата на прекъсвания се получават интересни резултати.

Terminal1

В тази програма има сложно условие за switch-а, като идеята е, ако отговаря на тези условия да влиза нормално в case-овете. Условията в скобките връщат винаги true или false, или техния еквивалент в цели числа – т.е. 1 или 0. Нещо умножено по 0 е 0, а нещо умножено по 1 си е самото нещо. Понеже нямаме break-ове изпълняваме всичко след като е влезнал в дадения case или default, така че позиционирането на конкретния случай наистина има значение.


#include <iostream>
using namespace std;

int main ()
{
	int x = 0;
	while (x < 5) 	{ 		
		switch (x * (x > -1) * (x < 4))
		{
			default: cout << "Not a number";
			case 1: cout << "A";
			case 2: cout << "B";
			case 3: cout << "C";
		}
		cout << endl;
		x++;
	}

	system("pause");
	return 0;
}

Terminal

Разликата с по-горната е, че default-а е най-горе, но винаги първо проверява всички case-ове и чак тогава намира default-a и изпълнява всичко след него, поради липсата на break.


#include <iostream>
using namespace std;

int main ()
{
	int x = 0;
	while (x < 5) 	{ 		
		switch (x * (x > -1) * (x < 4))
		{
			case 1: cout << "A";
			case 2: cout << "B";
			default: cout << "Not a number"; break;
			case 3: cout << "C";
		}
		cout << endl;
		x++;
	}

	system("pause");
	return 0;
}

Terminal

В последния код, default-а е в м/у case-овете и има break. Изходният резултат е видим в изображението под кода.

Тази публикация е с цел да обърне внимание на липсата на break и различното подреждане на case и default, в един switch.

Намиране на обиколката на фигура

Кодът по-долу е в помощ на курсистите по “Увод в програмирането“. Задачите изискват специфични умения и за това няма да бъдат натоварвани от излишни неща към този момент. Средата за разработка е Microsoft Visual Studio 2012, на някои от другите среди има нужда от добавяне на допълнителни библиотеки.

Идеята на задачата е да се намери обиколката на фигура съставена от две окръжности и две прави както е показано на изображението по-горе.

В началото въвеждаме координатите на двете точки, които принадлежат едновременно на права и окръжност. След това дефинираме променлива от тип double, в която ще пазим дължината на линията, в случая на двете линии взети заедно. Намирането на дължината на една линия става след като се извадят координатите на двата и края, но в случая координатите на края са (0;0) и няма да натоварваме излишно изчисленията. След като се вземат координатите на краищата се построяват прави по осите Х и У, така се получава правоъгълен триъгълник като катетите са разликата м/у Х координатите и У координатите. По Питагор се намира и дължината на хипотенузата (правата) , а тя е
C = sqrt(A^2 + B^2). Аналогично и за другата права и понеже търсим дължината на правите сумираме двете отсечки.

При намирането на радиуса на окръжността си използва същата логика от Питагоровата теорема. Понеже търсим дължина на 2-те окръжности, ги сумираме. Накрая записваме дължината на правите и окръжностите в обща променлива, която извеждаме.


#include <iostream>
using namespace std;

int main()
{
	int xPoint1, yPoint1;
	cout << "Enter the cordinates of the point on the circle1:" << endl;
	cin >> xPoint1 >> yPoint1;

	int xPoint2, yPoint2;
	cout << "Enter the cordinates of the point on the circle2:" << endl;
	cin >> xPoint2 >> yPoint2;

	double lengthLine = (sqrt(pow(xPoint1, 2) + pow(yPoint1, 2))) + 
		(sqrt(pow(xPoint2, 2) + pow(yPoint2, 2)));
	//In lengthLine calculate length of each line with Pythagorean theorem: 
	//hypotenuse = sqrt (cathetus1 ^ 2 + cathetus2 ^ 2)
	//Cathetus1 is subtraction between X coordinate of each points of the line
	//Cathetus2 is subtraction between Y coordinate of each points of the line

	int xCenter1, yCenter1;
	cout << "Enter the cordinates of the center on the circle1:" << endl;
	cin >> xCenter1 >> yCenter1;

	int xCenter2, yCenter2;
	cout << "Enter the cordinates of the center on the circle2:" << endl;
	cin >> xCenter2 >> yCenter2;

	double circuit = ((sqrt(pow(xPoint1 - xCenter1, 2) + pow(yPoint1 - yCenter1, 2))) * 2 * 3.14) + 
		((sqrt(pow(xPoint2 - xCenter2, 2) + pow(yPoint2 - yCenter2, 2))) * 2 * 3.14);
	//In the lengthCircle calculate length of the each circle like a calculating length of the line.
	//Again use Pythagorean theorem for find radius or diameter.
	//Next use formula for circuit.
	//Circuit = 2 * Pi * R or Circuit = Pi * D			R - radius	D - diameter

	double length = lengthLine + circuit;
	//At last collect length of lines and circles.
	
	cout << "Length of the figure is: " << length << endl;

	return 0;
}

Terminal